// 客户端文件
#include "Socket.hpp"
#include "Protocol.hpp"

#include <iostream>
#include <unistd.h>
#include <time.h>

void Usage(const std::string &proc)
{
    std::cout << "\n\rUsage: " << proc << " ip " << "port[1024+]\n"
              << std::endl;
}

//./client 127.0.0.1 8080
int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        Usage(argv[0]);
        exit(1);
    }
    std::string serverip = argv[1];
    uint16_t serverport = std::stoi(argv[2]);

    Sock clientsock;
    clientsock.Socket();
    clientsock.Connect(serverip, serverport);

    srand(time(nullptr) ^ getpid());
    int cnt = 10;
    // 如果格式正确，那么对于符号错误的情况，会进行处理，
    // 在switch case中会进入default选项，code设置Other_Oper
    const std::string opers = "+-*%/>=sch";
    std::string inbuffer_stream;
    while (cnt--)
    {
        int x = rand() % 100 + 1;
        int y = rand() % 100;
        usleep(4321);
        char op = opers[rand() % opers.size()];
        // 构建请求报文
        // 序列化
        Request req(x, y, op);
        std::cout << "构建新请求:" << x << op << y << "=?" << std::endl;
        std::string c_req_content;
        req.Serialize(&c_req_content);
        // 添加报头，构建完整报文
        std::string c_req_package = Encode(c_req_content);
        std::cout << "即将发送的报文：" << c_req_package << std::endl;
        //std::string c_req_package = "5\n1 + 2\n7\n10 + 20\n7\n20 + 30\n";  //一次发多组报文的测试，替换上面一直到while的所有
        // 发送报文
        write(clientsock._sockfd, c_req_package.c_str(), c_req_package.size());
        // 读取报文
        char buffer[128];
        ssize_t n = read(clientsock._sockfd, &buffer, sizeof(buffer));
        if (n > 0)
        {
            buffer[n] = 0; 
            inbuffer_stream += buffer;
            while (true) //处理一次发送多个报文，服务器计算多个数据，并返回多个报文的情况
            {
                //std::cout << inbuffer_stream << std::endl;
                if(!inbuffer_stream.size()) break;
                std::string s_rsp_content;
                int ret = Decode(inbuffer_stream, &s_rsp_content);
                if (!ret)
                    continue;

                Response resp;
                resp.Deserialize(s_rsp_content);
                std::cout << "result:" << resp._result << " code:" << resp._code << std::endl;
            }
        }
        else if (n == 0)
            break;
        else
            break;
    }
    clientsock.Close();
    return 0;
}

//为什么会有不完整的报文，对于我们用户层用write写入的一定是完整的报文，但是对于内核Tcp协议，他是否发的是完整的就不确定了。
//可能Server端的用户层不从内核接受网络信息缓冲区中取数据，那么就会导致Server端的接受缓冲区满了
//就可能会导致Server接受缓冲区剩余空间，不够Client端发送完整的报文，所以可能会发一半，等到有空间了在发送另一半。
//所以inbuffer_stream的功能也是为了保存半个报文，等到在读取时，和另一半报文进行拼接.

